package com.lmxdawn.api.dnf.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.wxpay.sdk.WXPay;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.lmxdawn.api.admin.entity.GoldCoin;
import com.lmxdawn.api.admin.entity.Jade;
import com.lmxdawn.api.admin.entity.Md;
import com.lmxdawn.api.admin.entity.Training;
import com.lmxdawn.api.admin.entity.auth.AuthAdmin;
import com.lmxdawn.api.admin.req.auth.AuthAdminQueryRequest;
import com.lmxdawn.api.admin.service.IGoldCoinService;
import com.lmxdawn.api.admin.service.IJadeService;
import com.lmxdawn.api.admin.service.IMdService;
import com.lmxdawn.api.admin.service.ITrainingService;
import com.lmxdawn.api.admin.service.auth.AuthAdminService;
import com.lmxdawn.api.admin.util.RedisUtil;
import com.lmxdawn.api.common.api.Constants;
import com.lmxdawn.api.common.session.SessionContextHolder;
import com.lmxdawn.api.common.util.IdWorker;
import com.lmxdawn.api.dnf.dto.*;
import com.lmxdawn.api.dnf.entity.OnlineRoomObj;
import com.lmxdawn.api.dnf.entity.Order;
import com.lmxdawn.api.dnf.entity.OrderItem;
import com.lmxdawn.api.dnf.mapper.OrderItemMapper;
import com.lmxdawn.api.dnf.mapper.OrderMapper;
import com.lmxdawn.api.dnf.service.IAlipayAccountService;
import com.lmxdawn.api.dnf.service.OrderService;
import com.lmxdawn.api.dnf.util.GoldTypeEnum;
import com.lmxdawn.api.im.service.ChatConstant;
import com.lmxdawn.api.im.service.ImUtil;
import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import lombok.var;
import org.jim.core.packets.ChatBody;
import org.jim.core.packets.UserMessageData;
import org.jim.server.JimServerAPI;
import org.jim.server.config.ImServerConfig;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.wechat.pay.java.service.refund.model.Status.PROCESSING;
import static com.wechat.pay.java.service.refund.model.Status.SUCCESS;
import static org.jim.core.packets.Command.COMMAND_CHAT_REQ;

@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    @Autowired
    private OrderMapper orderMapper;


    @Autowired
    private OrderItemMapper orderItemMapper;

    @Autowired
    private IGoldCoinService goldCoinService;

    @Autowired
    private WXPay wxPay;

    @Autowired
    private IdWorker idWorker;


    @Resource
    IAlipayAccountService accountService;

    @Resource
    RedissonClient redissonClient;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Resource
    private AuthAdminService authAdminService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SmsServiceImpl smsServiceImpl;

    @Override
    public AlipayConfig getConfig(String merchantOrderId) {
        Order order = this.getById(merchantOrderId);
        var account = accountService.lambdaQuery().last("limit 1").one();
        //获得初始化的AlipayClient
        //MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA598IlcmApsU+9E1HfLc17Fz1V5XcyB893t/1eKlMyQqa2rT85OFSHuvk4dncS7mxkl/TS9dprWTC8nDjreoOq06T19jLS8JjTwkRP+cjw8ai76Eji7PeUs3yQ/v8fXxP1eimbYegRYsgsqUmhPsN0qpB6E9ttEMU+k/oYhYnqHBR78mw9ipEUlakDUuyexMsAdORzXqJWn4Jb5IRItOPfga+S0A3bwmVLG1kGVS8pBgixNZ5/Umx/LUIjzxOcaz/pE3/XZ9/0fMMEnqwdM/r1r2HvO2XmsQZZqbBZPKP5sJvceQYCZkIUHRaYvfUpDRBT6bb+nFVsIJJbSTquKR8SQIDAQAB
//        val alipayConfig = new AlipayConfig();
//        alipayConfig.setAlipayPublicKey(account.getPublicKey());
//        alipayConfig.setMerchantPrivateKey(account.getPrivateKey());
//        alipayConfig.setAppId(account.getAppId());
//        alipayConfig.setGatewayUrl("https://openapi.alipay.com/gateway.do");
//        alipayConfig.setNotifyUrl("http://www.5808d.com/payment/alipay");
//        alipayConfig.setReturnUrl("http://www.5808d.com/order-detail");

        com.alipay.api.AlipayConfig alipayConfig = new com.alipay.api.AlipayConfig();
//设置网关地址
        alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
//设置应用APPID
        alipayConfig.setAppId(account.getAppId());
//设置应用私钥
        alipayConfig.setPrivateKey(account.getPrivateKey());
//设置应用公钥证书路径
        alipayConfig.setAppCertPath("/certs/" + account.getAppId() + "/appCertPublicKey.crt");
//设置支付宝公钥证书路径
        alipayConfig.setAlipayPublicCertPath("/certs/" + account.getAppId() + "/alipayCertPublicKey_RSA2.crt");
//设置支付宝根证书路径
        alipayConfig.setRootCertPath("/certs/" + account.getAppId() + "/alipayRootCert.crt");
//设置请求格式，固定值json
        alipayConfig.setFormat("json");
//设置字符集
        alipayConfig.setCharset("utf-8");
        return alipayConfig;
    }


    @Override
    public Long countMessage(String groupId, String userId) {
        val count = redisTemplate.opsForZSet().zCard(String.format("push:group:%s:%s", groupId, userId));
        return count;
    }

    @Override
    public List<OnlineRoomObj> listOnlineUser(AuthAdminQueryRequest request) {
        var messageHelper = ((ImServerConfig) JimServerAPI.imConfig).getMessageHelper();
        List<OnlineRoomObj> list = Lists.newArrayList();
        int start = (request.getPage() - 1) * request.getLimit();
        int end = request.getLimit() * request.getPage() - 1;
        List<Object> jimOnlineUser = redisUtil.lGet("JIM_ONLINE_USER", start, end);
        if (CollUtil.isEmpty(jimOnlineUser)) {
            return list;
        }
        var authAdmins = authAdminService.listByIds(jimOnlineUser);
        Map<String, AuthAdmin> userMap
                = authAdmins.stream().collect(Collectors.toMap(o -> o.getId().toString(), Function.identity()));
// todo
//        List<String> orderIds = jimOnlineUser.stream()
//                .map(Object::toString)
//                .filter(o -> !o.startsWith("user-")).collect(Collectors.toList());
//        List<Order> orders = this.listByIds(orderIds);
//        Map<String, Order> orderMap = orders.stream().collect(Collectors.toMap(o -> o.getId().toString(), Function.identity()));
        // userlist   online user存对象   放user id +
        jimOnlineUser.forEach(user -> {
            try {
                String userId = user.toString();
                val count = this.countMessage(userId, "admin");
                List lstMsg = this.fetchMessage(userId, userId, 1, 1);
                //
//                val chatBodies = offlineMessage
//                        .getGroups().get(user.getId().toString());
                OnlineRoomObj room = null;
                if (userId.startsWith("user-")) {
                    room = new OnlineRoomObj(userId,
                            "用户-" + userMap.get(userId).getUsername(), count, messageHelper.isOnline(userId), CollUtil.isEmpty(lstMsg) ? null : lstMsg.get(0));
                } else {
                    room = new OnlineRoomObj(userId,
                            "订单-" + userId,
                            count, messageHelper.isOnline(userId), CollUtil.isEmpty(lstMsg) ? null : lstMsg.get(0));
                }
                list.add(room);
            } catch (Exception exception) {
                log.error("===>{}", user);
                exception.printStackTrace();
            }
        });
        return list;
    }

    @Override
    public List fetchMessage(String roomId, String userId, Integer page, Integer pageSize) {
        var messageHelper = ((ImServerConfig) JimServerAPI.imConfig).getMessageHelper();
        if (pageSize == null) {
            pageSize = 20;
        }
        if (page == null) {
            page = 1;
            pageSize = 200;
        }
        int xpage;
        val count = redisTemplate.opsForZSet().zCard(String.format("store:group:%s", roomId));
        if (count % pageSize == 0) {
            xpage = (int) (count / pageSize);
        } else {
            xpage = (int) (count / pageSize) + 1;
        }// 107 = 6  offset = 107 - 20
        List<ChatBody> chatBodies;
        if (xpage < page) {
            chatBodies = Lists.newArrayList();
        } else {
            int offset = (int) (count - (pageSize * page));
            UserMessageData groupHistoryMessage = messageHelper
                    .getGroupHistoryMessage(userId, roomId, null, null,
                            offset > 0 ? offset : 0, pageSize);
//                (double) DateUtil.offsetDay(new Date(), -7).getTime(),
//                (double) DateUtil.thisMillisecond(), 0, 1000);
            chatBodies = groupHistoryMessage.getGroups().get(roomId);
        }

//        if (CollUtil.isNotEmpty(chatBodies)){
//            chatBodies = Lists.reverse(chatBodies);
//        }
        if (pageSize > 1) {
            var groupOfflineMessage = messageHelper.getGroupOfflineMessage(userId, roomId);
        }
//        val chatBodies = groupOfflineMessage.getGroups().get(roomId);
        return chatBodies == null ? Lists.newArrayList():chatBodies;
    }

    @Override
    public List joinRoom(String orderNo, String type, String currentUser) {
        Order order = this.findById(orderNo);
        if (order != null) {
            var messageHelper = ((ImServerConfig) JimServerAPI.imConfig).getMessageHelper();
            var groupUsers = messageHelper.getGroupUsers(orderNo);
            if (StrUtil.isNotBlank(order.getSaleId())) {
                String saleUser = order.getSaleId();
                if (!groupUsers.contains(saleUser)) {
                    messageHelper.addGroupUser(saleUser, orderNo);
                }
            }
            if (StrUtil.equals(type, "web")) {
                currentUser = "admin";
            }
            if (!groupUsers.contains(currentUser)) {
                messageHelper.addGroupUser(currentUser, orderNo);
            }
            String buyId = order.getUserId() + "";
            if (!groupUsers.contains(buyId)) {
                messageHelper.addGroupUser(buyId, orderNo);
            }
//        if (!StrUtil.equals(type, "web")){
//            ChatBody chatBody = new ChatBody.Builder()
//                    .content("购买须知 1111")
//                    .setCmd(Command.COMMAND_CHAT_REQ.getNumber())
//                    .chatType(1)
//                    .from("admin")
//                    .build();
//            ImPacket imPacket = new ImPacket(Command.COMMAND_CHAT_REQ, chatBody.toByte());
//            JimServerAPI.sendToGroup(orderNo,imPacket);
//        }
        }
        return fetchMessage(orderNo, currentUser, 1, 20);


    }

    @Override
    public void takeOrder(Order order) {
        Order orderData = this.getById(order.getId());
        if (orderData.getStatus() == 1) {
            throw new RuntimeException("订单已完成，不可接单");
        }
        if (orderData.getStatus() == 2) {
            throw new RuntimeException("订单已取消，不可接单");
        }
        if (orderData.getStatus() == 5) {
            throw new RuntimeException("订单已发货，不可接单");
        }
        if (orderData.getStatus() == 3) {
            throw new RuntimeException("订单已接单，不可重复操作");
        }
        if (orderData.getStatus() != 0) {
            throw new RuntimeException("订单当前状态不可接单");
        }
        this.lambdaUpdate()
                .set(Order::getStatus, 3)
                .set(Order::getUpdateTime, DateUtil.date())
                .eq(Order::getId, order.getId())
                .update();

        String msg = "商家已接单";
        if (orderData.getType() == 3 || orderData.getType() == 15) {
            msg = "商家已接单，等待商家上架装备中【务必核实商品名、价格在上下两页的唯一性，避免因重复导致拍错造成损失】";
        }
        String orderId = order.getId().toString();
        ChatBody build = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from("admin")
                .to(orderId)
                .content(msg)
                .setCmd(11)
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();
        ImUtil.sendToGroup(orderId, build);
        ChatBody build2 = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from("admin")
                .to(orderId)
                .content("")
                .setCmd(25)
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();
        ImUtil.sendToGroup(orderId, build2);
    }

    /**
     * 订单完成
     * 1、更新订单状态
     * 2、修改余额
     *
     * @param order
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void completed(Order order) {
        String id = order.getId();
        order = this.orderMapper.selectByPrimaryKey(id);
        this.lambdaUpdate()
                .set(Order::getStatus, 1)
                .set(Order::getUpdateTime, DateUtil.date())
                .eq(Order::getId, id)
                .update();
        Integer type = order.getType();
        // 1商城订单  只需要更新状态即可
        // 2寄售订单， 需要给售卖者的余额++
        if (type == 2 || type == 3) {
//            List<OrderItem> orderItems = orderItemMapper.queryByOrderIdIn(Sets.newHashSet(order.getId()));
//            val orderItem = orderItems.get(0);
//            Long productId = orderItem.getProductId();
//            GoldCoin product = goldCoinService.getById(productId);
            String saleUser = order.getSaleId();
            authAdminService.addWallet(saleUser, order.getTotalAmount(), order.getType(), order.getId());
        }
    }

    @Override
    public void deleteOrder(String orderId) {
        Order order = this.findById(orderId);
        if (order.getStatus() != 1 && order.getStatus() != 2) {
            throw new RuntimeException("订单当前状态不可删除");
        }
        this.lambdaUpdate().set(Order::getStatus, 4)
                .set(Order::getUpdateTime, DateUtil.date())
                .update();
    }

    @Override
    public void sendOrder(Order order) {
        Order orderData = this.getById(order.getId());
        if (orderData.getStatus() == 1) {
            throw new RuntimeException("订单已完成，不可发货");
        }
        if (orderData.getStatus() == 2) {
            throw new RuntimeException("订单已取消，不可发货");
        }
        if (orderData.getStatus() == 5) {
            throw new RuntimeException("订单已发货，不可重复发货");
        }
        if (orderData.getStatus() != 3) {
            throw new RuntimeException("订单当前状态不可发货");
        }
        String orderId = order.getId().toString();
        ChatBody build = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from("admin")
                .to(orderId)
                .content("订单已发货，请在60分钟内及时核实，如少/未收到货请及时反馈客服 如您已收到货，请及时确认收货")
                .setCmd(COMMAND_CHAT_REQ.getNumber())
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();
        ImUtil.sendToGroup(orderId, build);
        this.sendOrder(order.getId().toString());

    }

    public void sendOrder(String orderId) {
        this.lambdaUpdate().eq(Order::getId, orderId)
                .set(Order::getUpdateTime, DateUtil.date())
                .set(Order::getStatus, 5).update();
        ChatBody build2 = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from("admin")
                .to(orderId)
                .content("")
                .setCmd(ChatConstant.COMMAND_SEND_GOODS)
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();
        ImUtil.sendToGroup(orderId, build2);
        Order order = this.getById(orderId);
        String userId = order.getUserId();
        AuthAdmin buyer = authAdminService.findById(userId);
        if (buyer != null) {
            smsServiceImpl.sendBuyerNotify(orderId, buyer.getUsername());
        }
    }

    /**
     * 发货
     *
     * @param orderId
     * @param userId
     */
    @Override
    public void sendGoods(String orderId, String userId) {
        Order order = this.getById(orderId);
        if (order == null || (order.getStatus() != 0 && order.getStatus() != 3)) {
            throw new RuntimeException("订单状态异常");
        }
        if (order.getPaymentStatus() != 1) {
            throw new RuntimeException("订单未支付");
        }
        ChatBody build = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from("admin")
                .to(orderId)
                .content("订单已发货，请在60分钟内及时核实，如您已收到货，请及时确认收货")
                .setCmd(COMMAND_CHAT_REQ.getNumber())
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();

        ImUtil.sendToGroup(orderId, build);
        this.sendOrder(orderId);


    }

    private void orderCloseNotify(String orderId) {
        ChatBody build = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from("admin")
                .to(orderId)
                .content("会话已关闭")
                .setCmd(ChatConstant.COMMAND_CLOSE_ORDER)
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();

        ImUtil.sendToGroup(orderId, build);
    }

    /**
     * 1、订单状态变更完成
     * 2、 给发货人转钱
     * 3、如果是购买商城金币 则不需要转钱
     *
     * @param orderId
     * @param userId
     */
    @Override
    public void confirmReceive(String orderId, String userId, int type) throws InterruptedException {
        Order order = this.findById(orderId);
        if (order == null) {
            throw new RuntimeException("订单不存在");
        }
        if (order.getStatus() == 1) {
            throw new RuntimeException("订单已完成");
        }
        if (order.getStatus() == 2) {
            throw new RuntimeException("订单已取消");
        }
        if (order.getStatus() != 5) {
            throw new RuntimeException("订单未发货");
        }
        if (order.getPaymentStatus() != 1) {
            throw new RuntimeException("订单未支付");
        }
        String saleId = order.getSaleId();
        RLock lock = redissonClient.getLock("confirmReceiveLock-" + saleId);
        if (lock.tryLock(10, TimeUnit.SECONDS)) {
            try {
                String msg = "";
                if (type == 1) {
                    if (order.getType() == 3 || order.getType() == 15) {
                        msg = "订单已完成，商家确认收货。请在个人中心我的余额手动提现";
                    } else if (order.getType() == 2) {
                        msg = "订单已完成，买家确认收货。请在个人中心我的余额手动提现";
                    } else if (order.getType() == 1 || order.getType() == 11 || order.getType() == 13) {
                        msg = "订单已完成，买家确认收货。";
                    } else {
                        msg = "订单已完成，买家确认收货。请在个人中心我的余额手动提现";
                    }
                } else if (type == 2) {
                    msg = "订单已完成，系统自动确认。请在个人中心我的余额手动提现 ";
                }
                if (order.getType() == 2 || order.getType() == 3 || order.getType() == 15) {
                    authAdminService.addWallet(saleId, order.getTotalAmount(), order.getType(), order.getId());
                }
                this.lambdaUpdate().eq(Order::getId, orderId)
                        .set(Order::getUpdateTime, DateUtil.date()).set(Order::getStatus, 1).update();
                ChatBody build = ChatBody.newBuilder()
                        .chatType(1)
                        .groupId(orderId)
                        .from("admin")
                        .to(orderId)
                        .content(msg)
                        .setCmd(COMMAND_CHAT_REQ.getNumber())
                        .msgType(0)
                        .setCmd(11)
                        .setCreateTime(DateUtil.current())
                        .build();

                ImUtil.sendToGroup(orderId, build);
                this.orderCloseNotify(orderId);
            } catch (Exception e) {
                log.error("confirm error {}", e.getMessage());
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        } else {
            log.error("确认收货转账失败，订单：{}，用户：{}，金额：{}", orderId, saleId, order.getTotalAmount());
        }
    }

    @Override
    public boolean sendOrderByUser(String orderId, String userId) {
        Order orderData = this.getById(orderId);
        if (orderData.getStatus() == 1) {
            throw new RuntimeException("订单已完成，不可发货");
        }
        if (orderData.getStatus() == 2) {
            throw new RuntimeException("订单已取消，不可发货");
        }
        if (orderData.getStatus() == 5) {
            throw new RuntimeException("订单已发货，不可重复发货");
        }
        if (orderData.getStatus() != 3) {
            throw new RuntimeException("订单当前状态不可发货");
        }
        ChatBody build = ChatBody.newBuilder()
                .chatType(1)
                .groupId(orderId)
                .from(Arrays.asList( 3,15).contains(orderData.getType()) ? userId : "admin")
                .to(orderId)
                .content(
                        Arrays.asList(3,15).contains(orderData.getType())  ?
                                "发货完成" :
                                "订单已发货，请在60分钟内及时核实， 如您已收到货，请及时确认收货")
                .setCmd(COMMAND_CHAT_REQ.getNumber())
                .msgType(0)
                .setCreateTime(DateUtil.current())
                .build();
        ImUtil.sendToGroup(orderId, build);
        this.sendOrder(orderId);
        return true;
    }

    @Override
    public void confirmReceiveByAdmin(Order order) {

    }

    @Override
    public OrderTotalVo queryTotal(OrderTotalReq req) {
        List<String> orderTime = CollUtil.isNotEmpty(req.getOrderTime()) ? req.getOrderTime() : Lists.newArrayList(null, null);
        OrderTotalVo vo = this.orderMapper.queryOrderTotal(req.getServer(), orderTime.get(0), orderTime.get(1));
        OrderTotalVo vo1 = this.orderMapper.queryMonthOrderTotal(req.getServer());
        vo.setDyzycj(vo1.getDyzycj());
        vo.setDydbcj(vo1.getDydbcj());
        return vo;
    }

    /**
     * 1. 购买的订单
     * 2。出售的订单
     *
     * 如果是购买的订单， 则更新订单状态， 把钱退到购买人账户中
     * 如果是出售的订单，直接更新状态即可 3,15 回收金币
     * 如果是寄售的订单  给买家退钱
     * @param order
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancel(Order order) {
        Order detail = this.getById(order.getId());
        if (detail.getStatus() == 1 || detail.getStatus() == 2) {
            throw new RuntimeException("订单不可取消");
        }
        // 3 15 为回收的订单
        if (!Lists.newArrayList(3,15).contains(detail.getType())){
//            String userId = detail.getUserId();
//            authAdminService.addWallet(userId, detail.getTotalAmount());
            if (!this.refund(detail)){
                throw new RuntimeException("退款失败");
            }
        }
        detail.setStatus(2);
        detail.setUpdateTime(DateUtil.date());
        this.updateById(detail);
    }

    @Override
    public void test() {
        smsServiceImpl.sendTemplateMessageNotify("oi0g76qA8nFpL8dVoYIUsfYf5hxo");
    }

    @Override
    public UserOrderTotalVo getOrderInfo(String id) {
        return orderMapper.querySaleOrderTotalByUser(id);
    }


    /**
     * 查询全部列表
     *
     * @return
     */
    @Override
    public List<Order> findAll() {
        return orderMapper.selectAll();
    }

    /**
     * 根据ID查询
     *
     * @param id
     * @return
     */
    @Override
    public Order findById(String id) {
        if (id.startsWith("user-")) {
            return null;
        }
        Order order = orderMapper.selectByPrimaryKey(id);
        if (order == null) {
            return null;
        }
        return order;
    }

    /**
     * 增加
     *
     * @param order
     */
    @Override
    public void add(Order order) {
        orderMapper.insertOrder(order);
    }

    /**
     * 修改
     *
     * @param order
     */
    @Override
    public void update(Order order) {
        orderMapper.updateByPrimaryKey(order);
    }

    /**
     * 删除
     *
     * @param id
     */
    @Override
    public void delete(String id) {
        orderMapper.deleteByPrimaryKey(id);
    }

    @Override
    public void updatePayStatus(String orderId, String transactionId) {
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order != null && Constants.ZERO.equals(order.getPaymentStatus())) {//存在订单且状态为0-未支付
            order.setPaymentStatus(Constants.ONE);
//            order.setStatus(Constants.ONE);
            order.setUpdateTime(new Date());
            order.setPaymentTime(new Date());
            order.setTransactionId(transactionId);//第三方支付平台返回的交易流水号
            orderMapper.updateByPrimaryKey(order);
            if (StrUtil.isNotBlank(order.getSaleId())) {
                AuthAdmin user = authAdminService.findById(order.getSaleId());
                if (user != null) {
                    smsServiceImpl.sendSaleNotify(orderId, user.getUsername());
                }
            }
            //todo 记录订单变动日志
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void closeOrder(String orderId) {
        log.info("关闭订单开启：{}", orderId);
        Order order = orderMapper.selectByPrimaryKey(orderId);
        if (order == null) {
            log.warn("订单不存在：{}", orderId);
            return;
//            throw new RuntimeException("订单不存在！");
        }
        if (!Constants.ZERO.equals(order.getStatus())) {
            log.warn("此订单不用关闭：{}", orderId);
            return;
        }
        log.debug("关闭订单通过校验：{}", orderId);
        //判断支付方式调用对应的api查询支付结果，检测支付状态
        if (Constants.ZERO.equals(order.getPaymentMethod())) {
            Map<String, String> map = new HashMap<>();
            map.put("out_trade_no", orderId);
            Map<String, String> resultMap;
            try {
                resultMap = wxPay.orderQuery(map);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            log.info("查询微信支付订单结果：{}", resultMap);
            if ("SUCCESS".equals(resultMap.get("trade_state"))) { //如果支付状态是成功，进行补偿
                updatePayStatus(orderId, resultMap.get("transaction_id"));
                log.debug("补偿订单状态修改");
            } else if ("NOTPAY".equals(resultMap.get("trade_state"))) {  //如果是未支付，关闭订单
                log.info("未支付，关闭订单orderId:{}", orderId);
                order.setStatus(Constants.TWO);//订单状态
                order.setUpdateTime(new Date());//订单更新时间
                order.setPaymentStatus(Constants.TWO);//支付状态
                orderMapper.updateByPrimaryKey(order);//更新
                //恢复库存
                List<OrderItem> orderItemList = orderItemMapper.selectList2(orderId);
                for (OrderItem sku : orderItemList) {
                    goldCoinService.resumeStockNum(sku.getProductId(), sku.getQuantityOrder());
                }  //关闭微信订单

                try {
                    wxPay.closeOrder(map);
                } catch (Exception e) {
                    log.error("Error closing order：", e);
                }
            }
        } else if (Constants.ONE.equals(order.getPaymentMethod())) {
            //todo 调用支付宝接口
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String generateOrder(OrderDTO orderDTO, String userId) {
        switch (orderDTO.getTab()) {
            case "md":
                return this.mdOrder(orderDTO, userId);
            case "jade":
                return this.jadeOrder(orderDTO, userId);
            case "train":
                return this.trainOrder(orderDTO, userId);
            case "gold":
            default:
                return this.goldOrder(orderDTO, userId);

        }
    }


    @Resource
    IMdService mdService;
    @Resource
    ITrainingService trainingService;

    private Map<Integer, String> cateMap = new HashMap<Integer, String>(){{
        put(1, "包节日套");
        put(2, "强化增幅");
        put(3, "合龙袍天空");
        put(4, "pk代练");
        put(5, "等级代练");
        put(6, "深渊代练");
        put(7, "其他");
    }};

    @Resource
    IJadeService jadeService;
    private String trainOrder(OrderDTO orderDTO, String userId) {

        Training training = trainingService.getById(orderDTO.getProductId());
        Order order = new Order();
        //设置订单id
        order.setId(idWorker.orderNo("D"));
        order.setType(1);
        order.setGameServer(orderDTO.getGameServer());
        order.setPhone(orderDTO.getPhone());
        order.setGameUserName(orderDTO.getGameUserName());
        order.setGameUserLevel(orderDTO.getGameUserLevel());
        order.setPaymentMethod(orderDTO.getPaymentMethod());
        //单价
        order.setTotalAmount(new BigDecimal(training.getPrice())
                .multiply(orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP)));
        order.setStatus(Constants.ZERO);
        order.setPaymentStatus(Constants.ZERO);
        order.setUserId(SessionContextHolder.getId());
        order.setCreateTime(new Date());
        order.setSaleId("0");
        //新增订单数据
        OrderItem orderItem = new OrderItem();
        orderItem.setId(idWorker.nextId());
        orderItem.setProductId(orderDTO.getProductId());
        orderItem.setQuantityOrder(orderDTO.getQuantity());
        orderItem.setPrice(new BigDecimal(training.getPrice()));
        orderItem.setOrderId(order.getId());
        orderItemMapper.insertItem(orderItem);
        StringBuilder sb = new StringBuilder();
        sb.append("【");
        sb.append(cateMap.get(training.getCategory()));
        sb.append("】");
        sb.append(training.getTitle());
        order.setRemark(sb.toString());
        order.setRate(orderItem.getPrice());
        orderMapper.insertOrder(order);
        return order.getId().toString();
    }

    private String jadeOrder(OrderDTO orderDTO, String userId) {

        //扣减库存,根据OrderItem修改相关sku的库存信息

        Jade jade = jadeService.getById(orderDTO.getProductId());
        if (new BigDecimal(jade.getAmount()).doubleValue() - orderDTO.getQuantity().doubleValue() < 0) {
            throw new RuntimeException("库存不足,无法进行下单操作");
        }
        String saleUser = jade.getSaleUser();
        if (StrUtil.isNotBlank(saleUser) && userId.equals(saleUser)) {
            throw new RuntimeException("无法购买自己发布的商品！");
        }
        jadeService.deductStockNum(orderDTO.getProductId(), orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP));
        Order order = new Order();
        //设置订单id
        order.setId(idWorker.orderNo("B"));
        order.setType(jade.getType());
        order.setGameServer(orderDTO.getGameServer());
        order.setPhone(orderDTO.getPhone());
        order.setGameUserName(orderDTO.getGameUserName());
        order.setGameUserLevel(orderDTO.getGameUserLevel());
        order.setPaymentMethod(orderDTO.getPaymentMethod());
        //单价
        order.setTotalAmount(new BigDecimal(jade.getPrice())
                .multiply(orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP)));
        order.setStatus(Constants.ZERO);
        order.setPaymentStatus(Constants.ZERO);
        order.setUserId(SessionContextHolder.getId());
        order.setCreateTime(new Date());
        order.setSaleId(jade.getSaleUser());
        //新增订单数据
        OrderItem orderItem = new OrderItem();
        orderItem.setId(idWorker.nextId());
        orderItem.setProductId(orderDTO.getProductId());
        orderItem.setQuantityOrder(orderDTO.getQuantity());
        orderItem.setPrice(new BigDecimal(jade.getPrice()));
        orderItem.setOrderId(order.getId());
        orderItemMapper.insertItem(orderItem);
        StringBuilder sb = new StringBuilder();
        sb.append(jade.getLevel());
        sb.append(" : ");
        sb.append(orderItem.getPrice());
        sb.append("(元/个)");
        String attrs = jade.getAttrs();
        JSONObject attrObj = JSONObject.parseObject(attrs);
        if (StrUtil.isNotBlank(attrObj.getString("attr1Val"))){
            sb.append(attrObj.getString("attr1"));
            sb.append(" : ");
            sb.append(attrObj.getString("attr1Val"));
        }
        if (StrUtil.isNotBlank(attrObj.getString("attr2Val"))){
            sb.append(attrObj.getString("attr2"));
            sb.append(" : ");
            sb.append(attrObj.getString("attr2Val"));
        }
        if (StrUtil.isNotBlank(attrObj.getString("attr3Val"))){
            sb.append(attrObj.getString("attr3"));
            sb.append(" : ");
            sb.append(attrObj.getString("attr3Val"));
        }
        if (StrUtil.isNotBlank(attrObj.getString("attr4Val"))){
            sb.append(attrObj.getString("attr4"));
            sb.append(" : ");
            sb.append(attrObj.getString("attr4Val"));
        }
        order.setRemark(sb.toString());
        order.setRate(orderItem.getPrice());
        orderMapper.insertOrder(order);
        return order.getId().toString();
    }



    private String mdOrder(OrderDTO orderDTO, String userId) {
        //扣减库存,根据OrderItem修改相关sku的库存信息

        Md md = mdService.getById(orderDTO.getProductId());
        if (new BigDecimal(md.getAmount()).doubleValue() - orderDTO.getQuantity().doubleValue() < 0) {
            throw new RuntimeException("库存不足,无法进行下单操作");
        }
        String saleUser = md.getSaleUser();
        if (StrUtil.isNotBlank(saleUser) && userId.equals(saleUser)) {
            throw new RuntimeException("无法购买自己发布的商品！");
        }
        mdService.deductStockNum(orderDTO.getProductId(), orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP));
        Order order = new Order();
        //设置订单id
        order.setId(idWorker.orderNo("M"));
        order.setType(md.getType());
        order.setGameServer(orderDTO.getGameServer());
        order.setPhone(orderDTO.getPhone());
        order.setGameUserName(orderDTO.getGameUserName());
        order.setGameUserLevel(orderDTO.getGameUserLevel());
        order.setPaymentMethod(orderDTO.getPaymentMethod());
        //单价
        order.setTotalAmount(new BigDecimal(md.getQuantity()).multiply(orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP)));
        order.setStatus(Constants.ZERO);
        order.setPaymentStatus(Constants.ZERO);
        order.setUserId(SessionContextHolder.getId());
        order.setCreateTime(new Date());
        order.setSaleId(md.getSaleUser());
        //新增订单数据
        OrderItem orderItem = new OrderItem();
        orderItem.setId(idWorker.nextId());
        orderItem.setProductId(orderDTO.getProductId());
        orderItem.setQuantityOrder(orderDTO.getQuantity());
        orderItem.setPrice(new BigDecimal(md.getPrice()));
        orderItem.setOrderId(order.getId());
        orderItemMapper.insertItem(orderItem);
        orderItem.setOrderId(order.getId());
        StringBuilder sb = new StringBuilder();
        sb.append("矛盾");
        sb.append(" : ");
        sb.append(orderItem.getPrice());
        sb.append("(个/元)");
        sb.append(" * ");
        sb.append(orderItem.getQuantityOrder());
        order.setRemark(sb.toString());
        order.setRate(orderItem.getPrice());
        orderMapper.insertOrder(order);
        return order.getId().toString();
    }


    public String goldOrder(OrderDTO orderDTO, String userId){
        //扣减库存,根据OrderItem修改相关sku的库存信息
        GoldCoin goldCoin = goldCoinService.getById(orderDTO.getProductId());
        if (new BigDecimal(goldCoin.getAmount()).doubleValue() - orderDTO.getQuantity().doubleValue() < 0) {
            throw new RuntimeException("库存不足,无法进行下单操作");
        }
        String saleUser = goldCoin.getSaleUser();
        if (StrUtil.isNotBlank(saleUser) && userId.equals(saleUser)) {
            throw new RuntimeException("无法购买自己发布的商品！");
        }
        goldCoinService.deductStockNum(orderDTO.getProductId(), orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP));
        Order order = new Order();
        //设置订单id
        order.setId(idWorker.orderNo("A"));
        order.setType(goldCoin.getType());
        order.setGameServer(orderDTO.getGameServer());
        order.setPhone(orderDTO.getPhone());
        order.setGameUserName(orderDTO.getGameUserName());
        order.setGameUserLevel(orderDTO.getGameUserLevel());
        order.setPaymentMethod(orderDTO.getPaymentMethod());
        //单价
//         order.setTotalAmount(BigDecimal.valueOf(1));
        order.setTotalAmount(new BigDecimal(goldCoin.getQuantity()).multiply(orderDTO.getQuantity().setScale(2, RoundingMode.HALF_UP)));
        order.setStatus(Constants.ZERO);
        order.setPaymentStatus(Constants.ZERO);
        order.setUserId(SessionContextHolder.getId());
        order.setCreateTime(new Date());
        order.setSaleId(goldCoin.getSaleUser());
        //新增订单数据
        OrderItem orderItem = new OrderItem();
        orderItem.setId(idWorker.nextId());
        orderItem.setProductId(orderDTO.getProductId());
        orderItem.setQuantityOrder(orderDTO.getQuantity());
        orderItem.setPrice(new BigDecimal(goldCoin.getPrice()));
        orderItem.setOrderId(order.getId());
        StringBuilder sb = new StringBuilder();
        GoldTypeEnum typeEnum = goldCoin.getType() == null ? null : GoldTypeEnum.match(goldCoin.getType());
        sb.append(typeEnum == null ? "" : typeEnum.getLabel() );
        sb.append(" : ");
        sb.append(orderItem.getPrice());
        sb.append("(万金/元)");
        sb.append(" * ");
        sb.append(orderItem.getQuantityOrder());
        order.setRemark(sb.toString());
        order.setRate(orderItem.getPrice());
        orderMapper.insertOrder(order);
        orderItemMapper.insertItem(orderItem);
        return order.getId().toString();
    }

    public boolean refund(Order order) {
        Integer paymentMethod = order.getPaymentMethod();
        if (paymentMethod == 0){
            return this.alipayFund(order);
        }else{
            return this.wechatFund(order);
        }
    }
    @Resource
    WxpayConfig wxpayConfig;

    private boolean wechatFund(Order order) {
        Config config = new RSAAutoCertificateConfig.Builder()
                .merchantId(wxpayConfig.getMchID())
                .privateKeyFromPath(wxpayConfig.getPrivateKeyPath())
                .merchantSerialNumber(wxpayConfig.getSerialNumber())
                .apiV3Key(wxpayConfig.getApiV3Key())
                .build();
        RefundService refundService = new RefundService.Builder().config(config).build();
        CreateRequest request = new CreateRequest();

        request.setTransactionId(order.getTransactionId());
        request.setOutRefundNo(idWorker.nextId()+"");
        request.setReason("取消订单");
        request.setNotifyUrl("http://5808d.com/api/web/dnf/mall/payment/wxpay/notify");
        AmountReq amountReq = new AmountReq();
        amountReq.setTotal(order.getTotalAmount().multiply(BigDecimal.valueOf(101)).longValue());
        amountReq.setCurrency("CNY");
        amountReq.setRefund(order.getTotalAmount().multiply(BigDecimal.valueOf(101)).longValue());
        request.setAmount(amountReq);
        Refund refund = refundService.create(request);
        order.setRefundId(request.getOutRefundNo());
        log.info("=========wx refund : {}", JSON.toJSONString(refund));
        return (refund.getStatus() == SUCCESS || refund.getStatus() == PROCESSING) ;
    }

    private boolean alipayFund(Order order) {
        // 初始化SDK

        val alipayConfig = this.getConfig(order.getId());
        AlipayClient alipayClient = null;
        try {
            alipayClient = new DefaultAlipayClient(alipayConfig);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        log.info("===========>{}", alipayConfig.getAppId());
        // 构造请求参数以调用接口
        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
        AlipayTradeRefundModel  model = new AlipayTradeRefundModel();

        // 设置发红包时支付宝返回的支付宝订单号order_id
        model.setOutTradeNo(order.getId());
        // 设置标识一次资金退回请求
        model.setTradeNo(order.getTransactionId());
        // 设置需要退款的金额
        model.setRefundAmount(order.getTotalAmount()+"");
//        model.setRefundAmount("0.01");
        model.setRefundReason("订单取消");
        model.setOutRequestNo(idWorker.nextId()+"");

        request.setBizModel(model);
        request.setNotifyUrl("http://www.5808d.com/api/web/dnf/mall/payment/alipay");
        // 第三方代调用模式下请设置app_auth_token
        // request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
        AlipayTradeRefundResponse response = null;
        try {
            response = alipayClient.certificateExecute(request);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }

        order.setRefundId(model.getOutRequestNo());
        log.info("=======alipay Fund==>{}", JSON.toJSON(response));
        boolean res = "10000".equals(response.getCode());
        if (!res){
            return false;
        }
        if ("Y".equals(response.getFundChange())){
            this.lambdaUpdate().eq(Order::getId, order.getId())
                    .set(Order::getPaymentStatus, 3).update();
        }// 返回N是否会进行异步通知， 需要进一步确认
        return true;
    }
}
